
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include "Debug.h"
#include "Helper.h"
#include "configParser.h"
#include <libmemcached/memcached.h>
 
using namespace std;
Helper * Helper::_instance = NULL;

Helper::Helper() 
{
   m_lLasttime = 0;
   m_iEvents = 0;
   m_oTs = NULL;
   m_server_port = 0;
   m_iTime_gap = 10;
}

Helper::~Helper()
{
	
}

Helper * Helper::Instance(const char *confFile)
{
	if (NULL == _instance) 
	{
		_instance = new Helper();
		if ( !_instance->Startup(confFile) ) {
			delete _instance; 
			_instance = NULL;
		}
	}
	return _instance;
}

void Helper::Release(bool bForce)
{
	if (_instance) 
	{
		if(bForce)
		{
			delete _instance; 
			_instance = NULL;
		}
	}
}

bool  Helper::Startup(const char *confFile)
{
	if(confFile != NULL)
		m_sConfFile  = confFile;
	if(m_sConfFile.length() < 1)
	{
		ERRO<<": no helper.conf be given!"<<endl;
		return false;
	}
	struct stat st;
	if (lstat(confFile, &st) != 0)
	{
		ERRO<<":"<<confFile<<" is not exist!"<<endl;
		return false;
	}

	configParser cfg;
	map <string, string > g_Confs;
	g_Confs = cfg.Parser(confFile);
	if(g_Confs.size() <= 0)
	{
		cerr<<"error to explain conf :"<< confFile <<endl;
		return false;
	}
       
        map <string , string >::iterator iter;
        for(iter=g_Confs.begin(); iter != g_Confs.end(); iter++)
        {
             cout<< iter->first.c_str()<<"="<<iter->second.c_str()<<endl;
        }

	if( g_Confs.find("at_shell") != g_Confs.end())
		m_atShell  = g_Confs["at_shell"];

	if( g_Confs.find("shell") != g_Confs.end())
		m_shellscript  = g_Confs["shell"];
	if(m_shellscript.length() < 2)
	{
		cerr<<"No shell script"<< endl;	
		return false;
	}

	if( g_Confs.find("at") != g_Confs.end())
        {
		string sat = g_Confs["at"];
                m_oTs = new Tscheduler(sat);
        }
	
	if( g_Confs.find("server_port") != g_Confs.end())
        {
		string sat = g_Confs["server_port"];
		m_server_port = atoi(sat.c_str());
	}
	else
		return false;
	
	return true;
}

int Helper :: Timer(long lt, int gap)
{
	DEBUG1(" begin to Check!");
	if( m_server_port < 1)
		return 0;

	memcached_st * memc = memcached_create(NULL);
	memcached_return rc = MEMCACHED_SUCCESS;
	rc = memcached_server_add(memc,(char *)"127.0.0.1",(unsigned int)(m_server_port));
	if (rc != MEMCACHED_SUCCESS){
		perror("Connect to memcache server");
		memcached_free( memc );
		return 0;
	}
	memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, 1);
	memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT, 1);
	memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 0);

	char *keys[3 ];
	size_t key_length[3 ];

	keys[0] = (char *)"timer";
        char sgap[16]; 
	key_length[0] = 5;
	key_length[1] = sprintf( sgap, "%d", gap);
        keys[1] = (char *)sgap;
        keys[2] = (char *)"BIND-RESULT";
        key_length[2] = 11;
 
	memcached_result_st results_obj;
	memcached_result_st *results;
	results= memcached_result_create(memc, &results_obj);
	rc = memcached_mget(memc, keys, key_length, 3);
	memcached_result_free(&results_obj);
	memcached_free( memc );

/*
	DEBUG6("lt=", lt, "; events=", m_iEvents,"; lasttime=", m_lLasttime);
        if(m_oTs != NULL && m_oTs->Timer(lt+8*3600, m_iDefaultTimer))
                run_shell(m_atShell.c_str());
	else
	{
		DEBUG1("m_oTs is NULL or m_oTs->Timer == false or m_atShell is nulll");
	}
	if(lt < m_lLasttime + m_iDefaultTimer )
		return 0;
        if(m_iEvents <= 0 )
            return 0;

        run_shell(m_shellscript.c_str());
        m_lLasttime = lt; 
        m_iEvents = 0;
*/
	return 0;
}

int Helper:: Update(const char *key, int klen, int flags, time_t expire, const char *data, int dlen)
{
        return 0;
}

int Helper :: Process(map < int, string > &keys, conn *c)
{
	c->wbytes +=  sprintf(c->wcurr, "imok");
	int iSize = keys.size();
	if(iSize <= 0)
		return -1;
	int CMD = 1;
	string cmd = keys[CMD];
	if(cmd.compare("timer") == 0 && iSize == 3 )
	{ //timer + time_gap + END
	//	run_shell(m_shellscript.c_str());
                m_iTime_gap = atoi(keys[2].c_str());
                long lt = time(NULL);
		DEBUG6("lt=", lt, "; events=", m_iEvents,"; lasttime=", m_lLasttime);
		if(m_oTs != NULL && m_oTs->Timer(lt+8*3600, m_iTime_gap))
			run_shell(m_atShell.c_str());
		else
		{
			DEBUG1("m_oTs is NULL or m_oTs->Timer == false or m_atShell is nulll");
		}
		if(lt < m_lLasttime + m_iTime_gap )
			return 0;
		if(m_iEvents <= 0 )
			return 0;
cout<<"m_iEvents = "<< m_iEvents << endl;
		run_shell(m_shellscript.c_str());
		m_lLasttime = lt; 
		m_iEvents = 0;
	}
        return 0;
}

int Helper :: Process(const char *cmd, conn *c)
{
        DEBUG2("key = ", cmd);
         c->wbytes +=  sprintf(c->wcurr, "imok");
        if(strcmp("__stat__", cmd) == 0)
                return 0;
        m_iEvents++;
        long lt = time(NULL);
	if(lt < m_lLasttime + m_iTime_gap )
		return 0;
cout<< __func__<<":"<<__LINE__<<":"<< cmd << endl;
	run_shell(m_shellscript.c_str());
	m_lLasttime = lt; 
	m_iEvents = 0;
        return 0;
}


int Helper :: run_shell(const char *shell )
{
        if(shell == NULL)
               return -1;
	FILE *stream = NULL;
        string response;
	if((stream  =  popen(shell , "r"))   !=   NULL)
	{
		const int iSize = 1024;
		char szRead[iSize+1];
		int numread = 0;
		while(true)
		{
			memset(szRead,   0,   iSize);
			numread   =   fread(szRead,  1,  iSize,  stream);
			if(numread <= 0)
				break;
			else{
				szRead[numread] = '\0';
				response.append(szRead,numread) ;
			}
		}
		pclose(stream);
                DEBUG1(response);
cout<< response.c_str()<<endl;
                return 0;
	}
        return -2;
}


int Helper :: Check( void *args )
{
        int *port = (int *)args;
        DEBUG1(" begin to Check!");
        memcached_st * memc = memcached_create(NULL);
        memcached_return rc = MEMCACHED_SUCCESS;
        rc = memcached_server_add(memc,(char *)"127.0.0.1",(unsigned int)(*port));
        if (rc != MEMCACHED_SUCCESS){
                perror("Connect to memcache server");
                memcached_free( memc );
                return 0;
        }
        memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_NO_BLOCK, 1);
        memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_CONNECT_TIMEOUT, 1);
        memcached_behavior_set(memc, MEMCACHED_BEHAVIOR_BUFFER_REQUESTS, 0);
        size_t vlen;
        uint32_t flag;
        char *retval = memcached_get(memc,"__stat__", 8, &vlen, &flag, &rc);
        if (rc == MEMCACHED_SUCCESS){
                if (retval != NULL){
                        free(retval);
                }
        }
        if (rc != MEMCACHED_SUCCESS)
        {
                printf("Failure to communicate with servers (%s)\n", memcached_strerror(memc, rc));
                for(int i =0; i< 3; i++)
                {
                        usleep(100);
                        retval = memcached_get(memc, "__stat__", 8, &vlen, &flag, &rc);
                        if(rc == MEMCACHED_SUCCESS){
                                free(retval);
                                break;
                        }
                }
                if(rc != MEMCACHED_SUCCESS){
                        memcached_free(memc);
                        exit(1);
                        //abort();
                }
        }
        memcached_free( memc );
        DEBUG1("end Check!");
        return 0;
}

char * Helper :: Stats(char *ext_stats)
{
        string status;
        char hostname[128];
        gethostname(hostname, sizeof(hostname)) ;
        status.append("STAT server ");
        status.append(hostname);
 
        if(ext_stats != NULL)
                status.append(ext_stats);

        return (char *)status.c_str();
}

